package org.unicase.kineclipse.handlers;

/**
 * Client.java
 * 
 * Does all the basic I/O routines to connect to the Kinect and parse the events
 * 
 * @author engelman
 * @author daubersc
 * 
 * @version 1.0
 */
import static org.unicase.kineclipse.handlers.KinectEventsEnum.*;


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.HashMap;
import java.util.Map;
import java.util.StringTokenizer;

import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.Platform;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.IPerspectiveDescriptor;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PlatformUI;

public class Client {

	private Socket socket;
	private PrintWriter writer;
	private BufferedReader reader;
	private String message = "";
	private Map<String, HashMap<KinectEventsEnum, String>> perspectiveContainer;
	private String verb = "";
	private String command = "";

	private KinectEventsEnum eventToFire;
	public void openConnection() {

		new Thread(new Runnable() {
			public void run() {
				try {
					// Fill our config
					// TODO: Read from preferences instead of hard coding


					perspectiveContainer = new HashMap<String, HashMap<KinectEventsEnum, String>>();

					IConfigurationElement[] configurationElements = Platform.getExtensionRegistry().getConfigurationElementsFor("org.unicase.kineclipse.gestureCommandBindings");

					for(IConfigurationElement configElement: configurationElements){
						String perspective = configElement.getAttribute("perspective");
						HashMap<KinectEventsEnum, String> gestures;
						if(!perspectiveContainer.containsKey(perspective)){
							gestures = new HashMap<KinectEventsEnum, String>();
							perspectiveContainer.put(perspective, gestures);
						}
						else{
							gestures = perspectiveContainer.get(perspective);
						}
						String gesture = configElement.getAttribute("gesture");
						String command = configElement.getAttribute("command");
						gestures.put(KinectEventsEnum.valueOf(gesture), command);
					}

					socket = new Socket("127.0.0.1", 12345);
					writer = new PrintWriter(socket.getOutputStream(),true);

					// Tests
					KinectEventsEnum[] subscribtions = {INITSPEECH, STARTSPEECH, STOPSPEECH};

					reader = new BufferedReader(new InputStreamReader(socket
							.getInputStream()));
					subscribe(subscribtions);		    
					while (true) {
						try {
							processInput();
						} catch (Exception e) {
							e.printStackTrace();
						}

					}
				} catch (UnknownHostException e) {
					e.printStackTrace();
				} catch (IOException e) {
					e.printStackTrace();
				}

			}
		}).start();
	}

	protected void subscribe(KinectEventsEnum[] subscribtions) {
		for (KinectEventsEnum kee : subscribtions) {
			try {
				if(kee != INITSPEECH){
				writer.println(kee.toString());
				}
				else{
					writer.println(kee.toString() + "debug, step over");
				}
				String response = reader.readLine();
				if (!response.equalsIgnoreCase("OK")) {
					System.err.println("Subscribtion failed for " + kee.toString());
				}
			} catch (IOException ioe) {
				System.err.println("Subscribtion failed for " + kee.toString());
			}
		}


	}

	private void processInput() throws IOException {
		message = reader.readLine();
		if (message != null) {
			System.out.println(message);
			// Get verb
			String recog = "RECOGNIZED: ";
			if(message.startsWith(recog)){
				String word = message.substring(recog.length());
				fireSpeechEvent(word);
			}
			else{
			StringTokenizer st = new StringTokenizer(message, " ");
			verb = st.nextToken();
			// TODO: Add more sanity checks (NPE, ...)

			// Lookup gesture
				KinectEventsEnum evt = KinectEventsEnum.getEventByName(verb);
				eventToFire = evt;
				fireEvent();
			}
			

		}

	}



	private void fireEvent() {

		PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() {
			public void run() {
				String perspId = "";
				IWorkbenchWindow dwindow = PlatformUI.getWorkbench()
				.getActiveWorkbenchWindow();
				IWorkbenchPage page = dwindow.getActivePage();
				if (page != null) {
					IPerspectiveDescriptor desc = page.getPerspective();
					perspId = desc.getId();
				}
				System.out.println("In " + perspId + " perspective");

				command = perspectiveContainer.get(perspId).get(eventToFire);
				if (command!=null) {
					Display.getDefault().syncExec(new Runnable() {
						public void run() {
							EclipseActions.runCommand(command);
							// TODO: Add more alternatives than simply calling
							// the command (e.g. for commands that take
							// parameters);
						}
					});
				} else {
					System.err.println("Subscribed command " + verb + " not handled in this perspective!");
				}
			}


		});
	}
	
	private void fireSpeechEvent(final String recogWord) {

		PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() {
			public void run() {

				//put matching of command here
				if(recogWord.equals("debug")){
					Display.getDefault().syncExec(new Runnable() {
						public void run() {
							EclipseActions.runCommand("org.eclipse.debug.ui.commands.DebugLast");
						}
					});
				}
				if(recogWord.equals("step over")){
					Display.getDefault().syncExec(new Runnable() {
						public void run() {
							EclipseActions.runCommand("org.eclipse.debug.ui.commands.StepOver");
						}
					});
				}	
			}
		});
	}


	public void closeConnection() {
		try {
			writer.close();
			reader.close();
			socket.close();
		} catch (IOException e) {
			e.printStackTrace();
		}

	}



}
